package com.zkt.recommend.domain.algorithm;

import com.zkt.recommend.common.constants.HotQuestionProperties;
import com.zkt.recommend.common.constants.RecommendConstant;
import com.zkt.recommend.infra.entity.SubjectUserRecord;
import com.zkt.recommend.domain.redis.RedisUtil;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Component;

import java.time.Duration;
import java.time.LocalDateTime;

/**
 * @author 赵开泰
 * @program jc-club
 * @date 2025/3/28
 * @description 题目热度计算
 **/

@Component
public class HotQuestionCalculator {
	
	@Resource
	private RedisUtil redisUtil;
	
	@Resource
	private HotQuestionProperties properties;
	
	/**
	 * 计算并存储题目热度
	 */
	public void updateQuestionHotScore(SubjectUserRecord record) {
		if (record == null) {
			return;
		}
		
		// 计算最新热度评分
		double hotScore = calculateHotScore(record);
		
		// 读取 Redis 里已有的热度
		Double oldHotScore = redisUtil.score(RecommendConstant.HOT_QUESTIONS_KEY, record.getSubjectId());
		
		// 平滑更新：新热度 = α * 旧热度 + (1 - α) * 计算热度
		double alpha = properties.getAlpha();
		double newHotScore = (oldHotScore != null)
				? alpha * oldHotScore + (1 - alpha) * hotScore
				: hotScore;
		
		// 存入 ZSet（用于排序）
		redisUtil.zAdd(RecommendConstant.HOT_QUESTIONS_KEY, record.getSubjectId(), newHotScore);
	}
	
	/**
	 * 计算题目热度评分
	 */
	private double calculateHotScore(SubjectUserRecord record) {
		// 正确率权重
		double w1 = properties.getCorrectRate();
		// 平均耗时权重
		double w2 = properties.getAverageTime();
		// 题目完成时间权重
		double w3 = properties.getCreateTime();
		// 时间衰减系数
		double decayFactor = properties.getDecayFactor();
		// 中等时间值
		double middleUseTime = properties.getMiddleUseTime();
		
		// 计算正确率
		double correctRate = (record.getSubjectScore() > 0) ? ((double) record.getUserScore() / record.getSubjectScore()) : 0.0;
		
		// 计算时间衰减（基于完成时间 createdTime）
		double timeDecay = 1.0;
		if (record.getCreatedTime() != null) {
			long hoursSinceCompleted = Duration.between(record.getCreatedTime(), LocalDateTime.now()).toHours();
			timeDecay = Math.exp(-hoursSinceCompleted / decayFactor);
		}
		
		// 计算热度评分
		// 50% 正确率更受欢迎
		// 适中时间优先
		return w1 * (1 - Math.abs(0.5 - correctRate))
				+ w2 * (1 - Math.abs(middleUseTime - record.getUseTime()) / middleUseTime)
				+ w3 * timeDecay;
	}
	
}